package com.tiny.diamond.internal.util;


import com.tiny.diamond.DiamondApiException;
import com.tiny.diamond.DiamondConstants;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringWriter;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.*;

import javax.crypto.Cipher;


public class DiamondSignature {

    /**
     * RSA最大加密明文大小
     */
    private static final int MAX_ENCRYPT_BLOCK = 117;

    /**
     * RSA最大解密密文大小
     */
    private static final int MAX_DECRYPT_BLOCK = 128;

    /**
     * 获得需要签名的数据，按照参数名字母升序的顺序将所有参数用&连接起来。
     *
     * @param sortedParams 待签名的参数集
     * @return 排好序的待签名字符串
     */
    public static String getSignContent(Map<String, String> sortedParams) {
        StringBuffer content = new StringBuffer();
        List<String> keys = new ArrayList<String>(sortedParams.keySet());
        Collections.sort(keys);
        int index = 0;
        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            String value = sortedParams.get(key);
            if (StringUtils.areNotEmpty(key, value)) {
                content.append((index == 0 ? "" : "&") + key + "=" + value);
                index++;
            }
        }
        return content.toString();
    }


    public static String rsaSign(String content, String privateKey, String charset, String signType) throws DiamondApiException {
        if (DiamondConstants.SIGN_TYPE_RSA.equals(signType)){
            return rasSign(content,privateKey,charset);
        }else if(DiamondConstants.SIGN_TYPE_RSA2.equals(signType)){
            return null;
        }else{
            throw new DiamondApiException("Sign Type is Not Support ：signType ="+ signType);
        }
    }

    /**
     * sha1WithRsa 加签
     * @param content
     * @param privateKey
     * @param charset
     * @return
     * @throws DiamondApiException
     */
    public static String rasSign(String content,String privateKey,String charset) throws DiamondApiException{
        try {
            PrivateKey priKey = getPrivateKeyFromPKCS8(DiamondConstants.SIGN_TYPE_RSA, new ByteArrayInputStream(privateKey.getBytes()));
            Signature signature = Signature.getInstance(DiamondConstants.SIGN_ALGORITHMS);
            signature.initSign(priKey);

            if (StringUtils.isEmpty(charset)){
                signature.update(content.getBytes());
            }else {
                signature.update(content.getBytes(charset));
            }

            byte[] signd = signature.sign();

            return new String(Base64.getEncoder().encode(signd));
        } catch (InvalidKeySpecException ie) {
            throw new DiamondApiException("RSA私钥格式不正确，请检查是否正确配置了PKCS8格式的私钥", ie);
        } catch (Exception e) {
            throw new DiamondApiException("RSAcontent = " + content + "; charset = " + charset, e);
        }
    }

    public static PrivateKey getPrivateKeyFromPKCS8(String algorithm,InputStream inputStream) throws Exception{
        if (inputStream == null || StringUtils.isEmpty(algorithm)){
            return null;
        }

        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        byte[] encodedKey = StreamUtil.readText(inputStream).getBytes();

        encodedKey = Base64.getEncoder().encode(encodedKey);

        return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(encodedKey));
    }
}
